package com.zhanjixun.weixin.utils;

import lombok.extern.log4j.Log4j;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.apache.tika.mime.MimeTypeException;
import org.apache.tika.mime.MimeTypes;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

/**
 * HTTP请求工具
 *
 * @author :zhanjixun
 * @date : 2018/11/18 9:38
 */
@Log4j
public class HttpTools {

    private static final CookieStore COOKIE_STORE = new BasicCookieStore();
    //多个线程下使用可能会有异常
    private static final HttpClient HTTP_CLIENT = HttpClients.custom()
            .setDefaultCookieStore(COOKIE_STORE)
            .setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.92 Safari/537.36")
            .build();

    public static HttpResponse get(String url) {
        try {
            // log.info("GET " + url);
            return HTTP_CLIENT.execute(new HttpGet(url));
        } catch (IOException e) {
            throw new RuntimeException("执行GET请求失败");
        }
    }

    public static HttpResponse getNoRedirect(String url) {
        try {
            HttpGet request = new HttpGet(url);
            request.setConfig(RequestConfig.custom().setRedirectsEnabled(false).build());
            return HTTP_CLIENT.execute(request);
        } catch (IOException e) {
            throw new RuntimeException("执行GET请求失败");
        }
    }

    public static HttpResponse post(String url, String body) {
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(new StringEntity(body, ContentType.APPLICATION_JSON));
            return HTTP_CLIENT.execute(httpPost);
        } catch (IOException e) {
            throw new RuntimeException("执行POST请求失败");
        }

    }

    public static HttpResponse post(String url, HttpEntity entity) {
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(entity);
            return HTTP_CLIENT.execute(httpPost);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getCookie(String name) {
        return COOKIE_STORE.getCookies().stream().filter(d -> d.getName().equals(name)).map(Cookie::getValue).findFirst().orElse(null);
    }

    public static String toUTF8String(HttpResponse httpResponse) {
        try {
            return EntityUtils.toString(httpResponse.getEntity(), "UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static BufferedImage readImage(HttpResponse httpResponse) {
        try {
            return ImageIO.read(httpResponse.getEntity().getContent());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static File downloadFile(HttpResponse httpResponse, String fileName) {
        try {
            MimeTypes defaultMimeTypes = MimeTypes.getDefaultMimeTypes();
            String contentType = httpResponse.getEntity().getContentType().getValue();
            String fileExt = defaultMimeTypes.forName(contentType).getExtension();

            File file = U.newFile("download/" + fileName + fileExt);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            Source source = Okio.source(httpResponse.getEntity().getContent());
            BufferedSink buffer = Okio.buffer(Okio.sink(file));
            buffer.writeAll(source);
            buffer.flush();
            return file;
        } catch (MimeTypeException e) {
            throw new RuntimeException("无法识别ContentType的文件类型", e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static String formatJson(String jsonStr) {
        if (null == jsonStr || "".equals(jsonStr)) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        char last = '\0';
        char current = '\0';
        int indent = 0;
        boolean isInQuotationMarks = false;
        for (int i = 0; i < jsonStr.length(); i++) {
            last = current;
            current = jsonStr.charAt(i);
            switch (current) {
                case '"':
                    if (last != '\\') {
                        isInQuotationMarks = !isInQuotationMarks;
                    }
                    sb.append(current);
                    break;
                case '{':
                case '[':
                    sb.append(current);
                    if (!isInQuotationMarks) {
                        sb.append('\n');
                        indent++;
                        addIndentBlank(sb, indent);
                    }
                    break;
                case '}':
                case ']':
                    if (!isInQuotationMarks) {
                        sb.append('\n');
                        indent--;
                        addIndentBlank(sb, indent);
                    }
                    sb.append(current);
                    break;
                case ',':
                    sb.append(current);
                    if (last != '\\' && !isInQuotationMarks) {
                        sb.append('\n');
                        addIndentBlank(sb, indent);
                    }
                    break;
                default:
                    sb.append(current);
            }
        }

        return sb.toString();
    }


    private static void addIndentBlank(StringBuilder sb, int indent) {
        for (int i = 0; i < indent; i++) {
            sb.append('\t');
        }
    }
}
